﻿using System;
using Mnk.Merger.Code.Commands;
using Mnk.Merger.Code.Common;
using Mnk.Merger.Code.Repository;

namespace Mnk.Merger.Code.UI
{
    class MergeUi : IMergeUi
    {
        private readonly IMerger merger;
        private readonly IMergePathsBuilder mergePathsBuilder;
        private readonly IRepositoryFacade facade;

        public MergeUi(IMerger merger, IMergePathsBuilder mergePathsBuilder, IRepositoryFacade facade)
        {
            this.merger = merger;
            this.mergePathsBuilder = mergePathsBuilder;
            this.facade = facade;
        }

        public void Handle(string projectName)
        {
            while (true)
            {
                Console.WriteLine();
                Console.WriteLine();
                try
                {
                    if (!DoStep(projectName)) break;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                    return;
                }
            }
        }

        private bool DoStep(string projectName)
        {
            string workingDirectory, mergeUrl, revisions;
            if (!mergePathsBuilder.BuildParams(projectName, out workingDirectory, out mergeUrl, out revisions)) return false;
            PrintHelp();
            var cmd = Console.ReadLine();
            revisions = facade.GetLatestMergedRevisions(workingDirectory, mergeUrl);
            switch (cmd)
            {
                case "m":
                    Helpers.Handle(() => merger.DoMerge(workingDirectory, mergeUrl, revisions));
                    break;
                case "v":
                    Helpers.Handle(() => merger.DoValidation(workingDirectory));
                    break;
                case "c":
                    Helpers.Handle(() => merger.DoCommit(workingDirectory, mergeUrl, revisions));
                    break;
                case "C":
                    Helpers.Handle(() =>
                    {
                        merger.DoValidation(workingDirectory);
                        merger.DoCommit(workingDirectory, mergeUrl, revisions);
                    });
                    break;
                case "a":
                    Helpers.Handle(() => merger.DoAutoMerge(workingDirectory, mergeUrl, revisions, false));
                    break;
                case "A":
                    Helpers.Handle(() => merger.DoAutoMerge(workingDirectory, mergeUrl, revisions, true));
                    break;
                case "u":
                    Helpers.Handle(() => facade.Update(workingDirectory));
                    break;
                case "r":
                    Helpers.Handle(() =>
                    {
                        facade.CleanUp(workingDirectory);
                        facade.Revert(workingDirectory);
                    });
                    break;
                case "x":
                    return false;
                default:
                    Console.WriteLine("Unknown command: '{0}'", cmd);
                    break;
            }
            return true;
        }

        public void AutoMerge(string projectName, bool validate)
        {
            string workingDirectory, mergeUrl, revisions;
            if (!mergePathsBuilder.BuildParams(projectName, out workingDirectory, out mergeUrl, out revisions)) return;
            Helpers.Handle(() => merger.DoAutoMerge(workingDirectory, mergeUrl, revisions, validate));
        }
        
        private static void PrintHelp()
        {
            Console.Write(
@"Please, choose the next operation:
Basic:
m - Merge next revision - try to merge and if success - code will be merged.
v - Validate changes
c - Commit changes with auto generated message
a - Do auto merge. System will try to merge revision and if no error occurred, commit changes, continue until no conflicts.
x - exit

Advanced:
u - update folder
r - cleanup and revert changes
C - Validate and commit changes with auto generated message
A - Do safe auto merge. System will try to merge code, validate and if no error occurred, commit changes, revision by revision.
");
        }
    }
}